﻿using System;

namespace JSH.ITDiplom.OOPC01.PersonalIdentityNumber.BusinessLayer.da
{
    /// <summary>
    /// Modulus 11 validation for Danish personal identity number.
    /// </summary>
    public class Modulus11Validation : IPersonalIdentityNumberValidation
    {
        /// <summary>
        /// Inner class to handle birthDay and gender where modulus no
        /// longer is valid.
        /// </summary>
        public class NoModulus
        {
            public DateTime BirthDay { get; private set; }
            public Gender Gender { get; private set; }
            
            /// <summary>
            /// Constructor
            /// </summary>
            /// <param name="birthDay">Birthday</param>
            /// <param name="gender">Gender</param>
            public NoModulus(DateTime birthDay, Gender gender)
            {
                BirthDay = birthDay;
                Gender = Gender;
            }
        }
        
        /// <summary>
        /// List of birthdays and genders that don not support modulus 11
        /// see http://cpr.dk/cpr/site.aspx?p=23&t=ForsideVisartikel&Articleid=4347
        /// </summary>
        private static readonly NoModulus[] noModulus =
            {
                new NoModulus(new DateTime(1965, 1, 1), Gender.Male)
            };

        private static readonly int[] multiply = {4, 3, 2, 7, 6, 5, 4, 3, 2, 1};
        private readonly string personalIdentityNumber;
        private readonly DateTime? birthDay;
        private readonly Gender gender;

        public Modulus11Validation(string personalIdentityNumber, DateTime? birthDay,
            Gender gender)
        {
            this.personalIdentityNumber = personalIdentityNumber;
            this.birthDay = birthDay;
            this.gender = gender;
        }

        /// <summary>
        /// Validate.
        /// </summary>
        /// <returns>Returns true if personal identity number is valid.</returns>
        public bool Validate()
        {
            if (birthDay == null) return false;
            if (birthDay == noModulus[0].BirthDay && gender == noModulus[0].Gender) 
                return true;
            try
            {
                int sum = Sum(personalIdentityNumber, 10);
                if (sum % 11 == 0)
                {
                    return true;
                }
                return false;
            }
            catch (Exception)
            {
                return false;    
            }
        }

        private static int Sum(string str, int length)
        {
            int sum = 0;
            int pos = 0;
            for (int i = 0; i < length; i++)
            {
                sum += (Int32.Parse(str.Substring(pos, 1)) * multiply[i]);
                if (i == 5) pos++; //Ignore dash
                pos++;
            }
            return sum;            
        } 
        
        /// <summary>
        /// Calculate modulus 11 value.
        /// </summary>
        /// <param name="first10Chars">
        /// First 10 chars. of personal identity number
        /// </param>
        /// <returns>Modulus 11 value</returns>
        public static int Calculate(string first10Chars) 
        {
            int sum = Sum(first10Chars, 9);
            int remainder = sum % 11;
            if (remainder == 0) return 0;
            return 11 - remainder;
        }
    }
}
